import struct
from collections import namedtuple
import re
import sys

# 定义列描述结构
ColumnDescriptor = namedtuple(
    "ColumnDescriptor",
    [
        "catalog",
        "schema",
        "table",
        "org_table",
        "name",
        "org_name",
        "charset",
        "length",
        "type_code",
        "flags",
        "decimals",
    ],
)


def parse_length_encoded_int(data, pos):
    """解析长度编码整数"""
    if pos >= len(data):
        return None, pos
    first_byte = data[pos]
    pos += 1
    if first_byte < 0xFB:
        return first_byte, pos
    elif first_byte == 0xFC:
        return struct.unpack("<H", data[pos : pos + 2])[0], pos + 2
    elif first_byte == 0xFD:
        return struct.unpack("<I", data[pos : pos + 3] + b"\x00")[0], pos + 3
    elif first_byte == 0xFE:
        return struct.unpack("<Q", data[pos : pos + 8])[0], pos + 8
    return None, pos


def parse_length_encoded_string(data, pos):
    """解析长度编码字符串"""
    length, pos = parse_length_encoded_int(data, pos)
    if length is None or pos + length > len(data):
        return None, pos
    return data[pos : pos + length].decode("latin1"), pos + length


def parse_column_definition(data, pos):
    """解析列定义"""
    if pos + 4 > len(data):
        return None, pos

    # 跳过包头(4字节)
    packet_length = struct.unpack("<I", data[pos : pos + 3] + b"\x00")[0]
    pos += 4

    # 解析列定义
    catalog, pos = parse_length_encoded_string(data, pos)
    schema, pos = parse_length_encoded_string(data, pos)
    table, pos = parse_length_encoded_string(data, pos)
    org_table, pos = parse_length_encoded_string(data, pos)
    name, pos = parse_length_encoded_string(data, pos)
    org_name, pos = parse_length_encoded_string(data, pos)

    # 跳过下一个长度编码整数(通常是0x0c)
    if pos >= len(data) or data[pos] != 0x0C:
        return None, pos
    pos += 1

    # 解析字符集、长度、类型、标志和小数位
    if pos + 11 > len(data):
        return None, pos

    charset = struct.unpack("<H", data[pos : pos + 2])[0]
    pos += 2
    length = struct.unpack("<I", data[pos : pos + 4])[0]
    pos += 4
    type_code = data[pos]
    pos += 1
    flags = struct.unpack("<H", data[pos : pos + 2])[0]
    pos += 2
    decimals = data[pos]
    pos += 1

    # 跳过2字节填充
    pos += 2

    return (
        ColumnDescriptor(
            catalog,
            schema,
            table,
            org_table,
            name,
            org_name,
            charset,
            length,
            type_code,
            flags,
            decimals,
        ),
        pos,
    )


def parse_row(data, pos, column_count):
    """解析行数据"""
    if pos + 4 > len(data):
        return None, pos

    # 跳过包头(4字节)
    pos += 4

    row = []
    for _ in range(column_count):
        if pos >= len(data):
            break
        value, pos = parse_length_encoded_string(data, pos)
        row.append(value)

    return row, pos


def parse_resultset(data):
    """解析完整的ResultSet"""
    pos = 0
    if len(data) < 5:
        return [], []

    # 1. 解析列数量
    column_count = data[4]  # 跳过4字节包头
    print(f"列数量: {column_count}")
    pos = 5

    # 2. 解析列定义
    columns = []
    for _ in range(column_count):
        if pos >= len(data):
            break
        column, pos = parse_column_definition(data, pos)
        if column is None:
            break
        columns.append(column)
        print(f"列定义: {column.name} (类型: {column.type_code})")

    # 3. 解析EOF包(可选)
    if pos + 5 <= len(data) and data[pos + 4] == 0xFE:  # EOF包
        pos += 9

    # 4. 解析行数据
    rows = []
    while pos < len(data):
        if pos + 4 > len(data):
            break
        if data[pos + 4] == 0xFE:  # EOF包
            break
        row, pos = parse_row(data, pos, column_count)
        if row is None:
            break
        rows.append(row)
        print(f"行数据: {row}")

    # 添加结果验证
    if len(rows) > 0 and len(rows[0]) != len(columns):
        print("警告：列数与行数据不匹配！")

    return columns, rows


def read_hex_data_from_file(filename):
    """从文件读取十六进制数据并转换为二进制"""
    try:
        with open(filename, 'r') as f:
            # 读取文件内容并移除所有空白字符
            hex_data = ''.join(line.strip() for line in f)
            # 移除所有非十六进制字符
            hex_data = re.sub(r'[^0-9a-fA-F]', '', hex_data)
            return bytes.fromhex(hex_data)
    except FileNotFoundError:
        print(f"错误: 文件 '{filename}' 未找到")
        sys.exit(1)
    except ValueError as e:
        print(f"十六进制转换错误: {e}")
        sys.exit(1)


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python3 script.py <hex_data_file>")
        sys.exit(1)
    
    filename = sys.argv[1]
    binary_data = read_hex_data_from_file(filename)
    
    # 解析ResultSet
    columns, rows = parse_resultset(binary_data)